﻿using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;

namespace YunQue.Core.Common.QuartzManager
{
    /// <summary>
    /// 调度器管理类
    /// </summary>
    public class SchedulerManager
    {
        private readonly IScheduler _scheduler;
        public SchedulerManager()
        {
            _scheduler = StdSchedulerFactory.GetDefaultScheduler().Result;
            _scheduler.Start().Wait();
            InitJobs();
        }
        /// <summary>
        /// 初始化所有的任务
        /// </summary>
        private void InitJobs()
        {
            //从数据库加载持久化的任务信息并重新创建任务，此处省略
            List<(string JobName, string Content, string Cron)> persistedJobs = new List<(string, string, string)>();
            foreach (var jobInfo in persistedJobs)
            {
                CreateJobAsync(jobInfo.JobName, jobInfo.Content, jobInfo.Cron).Wait();
            }
        }
        /// <summary>
        /// 创建定时任务
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="content"></param>
        /// <param name="cron"></param>
        /// <returns></returns>
        private async Task CreateJobAsync(string jobName, string content, string cron)
        {
            IJobDetail job = JobBuilder.Create<SchedulerJob>()
                .WithIdentity(jobName, ConfigManager.JOB_GROUP_NAME)
                .UsingJobData(ConfigManager.JOB_DATA_KEY, content)
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity($"{ConfigManager.TRIGGER_PREFIX}{jobName}", ConfigManager.JOB_GROUP_NAME)
                .StartNow()
                .WithCronSchedule(cron, x => x.WithMisfireHandlingInstructionFireAndProceed())
                .Build();
            await _scheduler.ScheduleJob(job, trigger).ConfigureAwait(false);
        }
        /// <summary>
        /// 创建定时任务
        /// </summary>
        /// <param name="param"></param>
        /// <param name="jobName"></param>
        /// <param name="cron"></param>
        /// <returns></returns>
        public async Task CreateJobAsync(JobExecuteParam param,string jobName,string cron)
        {
            if(string.IsNullOrWhiteSpace(jobName))
            {
                throw new ArgumentNullException(nameof(jobName), "任务名称不能为空");
            }
            if(string.IsNullOrWhiteSpace(cron)) throw new ArgumentNullException(nameof(cron), "Cron表达式不能为空");
            if (param == null) throw new ArgumentNullException(nameof(param), "任务参数不能为空");
            if(string.IsNullOrWhiteSpace(param.WebhookUrl)) throw new ArgumentNullException(nameof(param.WebhookUrl), "任务回调地址不能为空");

            await CreateJobAsync(jobName, Newtonsoft.Json.JsonConvert.SerializeObject(param), cron).ConfigureAwait(false);
        }
        /// <summary>
        /// 暂停任务
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task PauseJobAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            await _scheduler.PauseJob(jobKey).ConfigureAwait(false);
        }
        /// <summary>
        /// 恢复任务
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task ResumeJobAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            await _scheduler.ResumeJob(jobKey).ConfigureAwait(false);
        }
        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task DeleteJobAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            await _scheduler.DeleteJob(jobKey).ConfigureAwait(false);
        }

        /// <summary>
        /// 立即执行任务
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task TriggerJobAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            bool exists = await _scheduler.CheckExists(jobKey).ConfigureAwait(false);
            if (!exists)
            {
                throw new Exception($"任务 {jobName} 不存在，无法触发执行");
            }
            string tiggerId = Guid.NewGuid().ToString();
            ITrigger immediaterTrigger = TriggerBuilder.Create()
                .WithIdentity($"{ConfigManager.IMMEDIATE_KEY}{tiggerId}", ConfigManager.JOB_GROUP_NAME)
                .StartNow()
                .ForJob(jobKey)
                .WithSchedule(SimpleScheduleBuilder.Create().WithRepeatCount(0)) // 只执行一次
                .Build();
            await _scheduler.ScheduleJob(immediaterTrigger).ConfigureAwait(false);
        }

        /// <summary>
        /// 获取所有任务
        /// </summary>
        /// <returns></returns>
        public async Task<IList<string>> GetAllJobsAsync()
        {
            var jobKeys = await _scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup()).ConfigureAwait(false);
            return jobKeys.Select(jk => jk.Name).ToList();
        }
        /// <summary>
        /// 获取任务详情
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task<IJobDetail> GetJobDetailAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            return await _scheduler.GetJobDetail(jobKey).ConfigureAwait(false);

        }
        /// <summary>
        /// 获取任务状态
        /// </summary>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public async Task<JobInfo> GetJobStateAsync(string jobName)
        {
            JobKey jobKey = new JobKey(jobName, ConfigManager.JOB_GROUP_NAME);
            bool exists = await _scheduler.CheckExists(jobKey).ConfigureAwait(false);
            if (!exists)
            {
                return new JobInfo()
                {
                    IsExists = false,
                };
            }
            // 获取任务的触发器
            var triggers = await _scheduler.GetTriggersOfJob(jobKey).ConfigureAwait(false);
            // 判断是否正在执行
            var executingJobs = await _scheduler.GetCurrentlyExecutingJobs().ConfigureAwait(false);
            bool isRunning = executingJobs.Any(ctx => ctx.JobDetail.Key.Equals(jobKey));
            return new JobInfo()
            {
                IsExists = true,
                IsRunning = isRunning,
                JobName = jobName,
                LastRunTime = triggers.Max(t => t.GetPreviousFireTimeUtc()?.LocalDateTime ?? DateTime.MinValue),
                NextRunTime = triggers.Min(t => t.GetNextFireTimeUtc()?.LocalDateTime ?? DateTime.MaxValue),
                Status = await _scheduler.GetTriggerState(triggers.OrderByDescending(x => x.GetPreviousFireTimeUtc()?.LocalDateTime ?? DateTime.MinValue).First().Key).ConfigureAwait(false)
            };
        }

    }
}
